﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Linq;
using System.Collections.ObjectModel;
using System.Collections.Generic;

namespace Transportr
{
    public class LineDetailsItemViewModel : BaseItemViewModel
    {
        private class tRecord
        {
            public DateTime fix;
            public int min;
            public int max;
        }

        private bool mReverseRoute;
        private StationViewModel mCurrentStation;
        private string mLineNumber;
        private string mCompany;
        private string mLineIconPath;
        private string mStatusText;
        private string mPrevStationName;
        private DateTime mCurrentDate;

        public ServiceModel.Terms RawTerms;
        public ServiceModel.LineInfo RawStations;
        public ServiceModel.Line RawBrief;
        public ObservableCollection<StationViewModel> RouteA;
        public ObservableCollection<StationViewModel> RouteB;

        public void RemoveFromFavorites()
        {
            // TODO: warning feldobasa, hogy biztosan torlod-e, mert akkor ezek es ezek a favorite route-ok is torlodnek
            // NOTE: persze csak azutan, hogy elkeszel a favroute model :)

            FavoriteStore.Store.Lines.Remove(
                FavoriteStore.Store.Lines.FirstOrDefault(
                o => o.Brief.lnId == this.RawBrief.lnId)
            );

            FavoriteStore.Save();
            NotifyPropertyChanged("IsFavorite");
        }

        public void AddToFavorites()
        {
            FavoriteStore.Store.Lines.Remove(
                FavoriteStore.Store.Lines.FirstOrDefault(
                o => o.Brief.lnId == this.RawBrief.lnId)
            );

            FavoriteStore.Store.Lines.Add(new FavoriteStore.LineDetails()
            {
                Terms = this.RawTerms,
                Brief = this.RawBrief,
                Stations = this.RawStations,
                NumberOfUses = 0
            });

            FavoriteStore.Save();
            NotifyPropertyChanged("IsFavorite");
        }

        public bool IsFavorite
        {
            get
            {
                return (this.RawBrief.lnId == 0 || FavoriteStore.Store.Lines.Any(e => e.Brief.lnId == this.RawBrief.lnId));
            }
        }


        public Visibility IsFavoriteVisibility
        {
            get
            {
                if (IsFavorite)
                    return Visibility.Visible;
                else
                    return Visibility.Collapsed;
            }
        }

        public ObservableCollection<StationViewModel> CurrentRoute
        {
            get
            {
                if (mReverseRoute)
                    return RouteB;
                else
                    return RouteA;
            }
        }

        public StationViewModel CurrentStation
        {
            get {
                if (mCurrentStation == null)
                {
                    mCurrentStation = CurrentRoute[0];
                }
                return mCurrentStation;
            }
            set
            {
                if (value != mCurrentStation)
                {
                    mCurrentStation = value;
                    NotifyPropertyChanged("CurrentStation");
                    if (value != null)
                    {
                        mPrevStationName = value.Name;
                        NotifyPropertyChanged("Timetable");
                    }
                }
            }
        }

        public DateTime CurrentDate
        {
            get { return mCurrentDate; }
            set
            {
                if (value != mCurrentDate)
                {
                    mCurrentDate = value;
                    NotifyPropertyChanged("CurrentDate");
                    NotifyPropertyChanged("Timetable");
                }
            }
        }

        public string CurrentRouteString
        {
            get
            {
                return String.Format("{0}\n{1}", CurrentRoute[0].Station.stName, CurrentRoute[CurrentRoute.Count - 1].Station.stName);
            }
        }

        private int getDayId(DateTime Date)
        {
            return ((int)Date.DayOfWeek + 6) % 7 + 1;
        }

        private List<int> getTermIds(DateTime Date)
        {
            List<int> ret = new List<int>();
            foreach (ServiceModel.Term term in RawTerms.Term)
            {
                foreach (ServiceModel.TermDate td in term.TermDate)
                {
                    DateTime from = DateTime.ParseExact(td.teDateFrom, "yyyy-MM-dd", ServiceModel.Helper.DatetimeFormat);
                    DateTime to = DateTime.ParseExact(td.teDateTo, "yyyy-MM-dd", ServiceModel.Helper.DatetimeFormat);
                    if (DateTime.Compare(CurrentDate, from) >= 0 && DateTime.Compare(CurrentDate, to) <= 0)
                        ret.Add(term.teId);
                }
            }
            return ret;
        }

        public ObservableCollection<TimetableItemViewModel> Timetable
        {
            get
            {
                List<tRecord> w = new List<tRecord>();
                TimeSpan maxTimeOffset = TimeSpan.FromMinutes((from svm in CurrentRoute
                                                               select svm.Station.slTime).Max());
                TimeSpan myOffset = TimeSpan.FromMinutes(CurrentStation.Station.slTime);
                for (int i = 0 - maxTimeOffset.Days; i <= 0; i++) // crazy counter to count with buses from the past
                {
                    TimeSpan currentDayOffset = TimeSpan.FromDays(i);
                    DateTime currentDate = CurrentDate.Subtract(currentDayOffset);
                    foreach (ServiceModel.Timetable t in CurrentRoute[0].Station.Timetable)
                    {
                        if (getTermIds(currentDate).Contains(t.teId) && t.ttDay.Contains(getDayId(currentDate).ToString()))
                        {
                            // this is a min/max record, add concrete time from the previous record, or t.ttHour:0 if not present
                            if (t.ttFixMin == 0 && !(t.ttMaxMin == 0 || t.ttMinMin == 0))
                            {
                                DateTime last = w.LastOrDefault().fix;

                                if (last != null && last.Hour == t.ttHour)
                                    w.Add(new tRecord()
                                    {
                                        fix = new DateTime(currentDate.Year, currentDate.Month, currentDate.Day, t.ttHour, last.Minute, 0),
                                        min = t.ttMinMin,
                                        max = t.ttMaxMin
                                    });
                                else
                                    w.Add(new tRecord()
                                    {
                                        fix = new DateTime(currentDate.Year, currentDate.Month, currentDate.Day, t.ttHour, 0, 0),
                                        min = t.ttMinMin,
                                        max = t.ttMaxMin
                                    });
                            }
                            // this is a fixed record
                            else
                            {
                                w.Add(new tRecord()
                                {
                                    fix = new DateTime(currentDate.Year, currentDate.Month, currentDate.Day, t.ttHour, t.ttFixMin, 0),
                                });
                            }
                        }
                    }
                }
                // list buliding finished, now shift the whole fucking list

                ObservableCollection<TimetableItemViewModel> ret = new ObservableCollection<TimetableItemViewModel>();
                for (int i = 0; i < w.Count; i++)
                {
                    w[i].fix = w[i].fix.Add(myOffset);

                    if (CurrentDate.Date == w[i].fix.Date)
                    {
                        if (!ret.Any(o => o.Hour == w[i].fix.Hour))
                            ret.Add(new TimetableItemViewModel() { Hour = w[i].fix.Hour });
                        string r;
                        if (w[i].min != 0)
                        {
                            if (w[i].min == w[i].max)
                                r = String.Format("{0} {1}", w[i].min, "min "); // TODO: replace static string to resource (multilang)
                            else
                                r = String.Format("{0}-{1} {2}", w[i].min, w[i].max, "min ");
                            // relative item slips into the next hour if its fixtime.min + offset > MAGiC-constant :)
                            if (i < w.Count - 1 && w[i+1].min == 0 && w[i+1].fix.Minute > w[i].max)
                            {
                                if (!ret.Any(o => o.Hour == w[i].fix.Hour + 1))
                                    ret.Add(new TimetableItemViewModel() { Hour = w[i].fix.Hour + 1 });
                                ret.First(o => o.Hour == w[i].fix.Hour + 1).Record += r;
                            }
                        }
                        else
                        {
                            r = String.Format("{0:D2} ", w[i].fix.Minute);
                        }
                        ret.First(o => o.Hour == w[i].fix.Hour).Record += r;
                    }
                }
                return ret;
            }
        }

        public string StatusText
        {
            get { return mStatusText; }
            set
            {
                if (value != mStatusText)
                {
                    mStatusText = value;
                    NotifyPropertyChanged("StatusText");
                    NotifyPropertyChanged("StatusVisible");
                }
            }
        }

        public bool StatusVisible
        {
            get
            {
                return mStatusText.Length > 0;
            }
        }

        public bool ReverseRoute
        {
            get { return mReverseRoute; }
            set
            {
                if (value != mReverseRoute)
                {
                    mReverseRoute = value;
                    CurrentStation = CurrentRoute.FirstOrDefault(s => s.Name == mPrevStationName);
                    NotifyPropertyChanged("ReverseRoute");
                    NotifyPropertyChanged("CurrentRoute");
                    NotifyPropertyChanged("CurrentRouteString");
                    NotifyPropertyChanged("Timetable");
                }
            }
        }

        public string LineNumber
        {
            get { return mLineNumber; }
            set
            {
                if (value != mLineNumber)
                {
                    mLineNumber = value;
                    NotifyPropertyChanged("LineNumber");
                }
            }
        }

        public string Company
        {
            get { return mCompany; }
            set
            {
                if (value != mCompany)
                {
                    mCompany = value;
                    NotifyPropertyChanged("Company");
                }
            }
        }

        public string LineIconPath
        {
            get { return mLineIconPath; }
            set
            {
                if (value != mLineIconPath)
                {
                    mLineIconPath = value;
                    NotifyPropertyChanged("LineIconPath");
                }
            }
        }

        public LineDetailsItemViewModel()
        {
            this.mCurrentDate = DateTime.Now;
            this.mStatusText = "";
        }
    }
}
